|
Extension functions
|
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
|
public struct Array<Element> {
mutating func swapAt(_ i: Int, _ j: Int)
}
|
val list = mutableListOf(1, 2, 3)
list.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'list'
|
var list = [1, 2, 3]
list.swapAt(0, 2)
|
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
|
|
Extensions are resolved statically
|
open class Shape
class Rectangle: Shape()
fun Shape.getName() = "Shape"
fun Rectangle.getName() = "Rectangle"
fun printClassName(s: Shape) {
println(s.getName())
}
printClassName(Rectangle())
|
Overriding declarations in extensions is not supported
|
class Example {
fun printFunctionType() { println("Class method") }
}
fun Example.printFunctionType() { println("Extension function") }
Example().printFunctionType()
|
class Example {
func printFunctionType() { print("Class method") }
}
extension Example {
//Error: Invalid redeclaration of 'printFunctionType()'
func printFunctionType() { print("Extension function") }
}
Example().printFunctionType()
|
class Example {
fun printFunctionType() { println("Class method") }
}
fun Example.printFunctionType(i: Int) { println("Extension function") }
Example().printFunctionType(1)
|
class Example {
func printFunctionType() { print("Class method") }
}
extension Example {
func printFunctionType(i: Int) { print("Extension function") }
}
Example().printFunctionType(i: 1)
|
Nullable receiver
|
fun Any?.toString(): String {
if (this == null) return "null"
// after the null check, 'this' is autocast to a non-null type, so the toString() below
// resolves to the member function of the Any class
return toString()
}
|
extension Optional {
func toString() -> String {
guard let x = self else {
return "nil"
}
return "\(x)"
}
}
|
Extension properties
|
val <T> List<T>.lastIndex: Int
get() = size - 1
|
extension Array {
var lastIndex: Int {
get {
return count - 1
}
}
}
|
val House.number = 1 // error: initializers are not allowed for extension properties
|
extension House {
var number: Int {
get { 1 }
}
}
|
Companion object extensions
|
class MyClass {
companion object { } // will be called "Companion"
}
fun MyClass.Companion.printCompanion() { println("companion") }
fun main() {
MyClass.printCompanion()
}
|
class MyClass {}
extension MyClass {
static func printCompanion() { print("static") }
}
MyClass.printCompanion()
|
Scope of extensions
|
package org.example.declarations
fun List<String>.getLongestString() { /*...*/}
|
extension Array where Element == String {
func getLongestString() -> String {
return "..."
}
}
|
package org.example.usage
import org.example.declarations.getLongestString
fun main() {
val list = listOf("red", "green", "blue")
list.getLongestString()
}
|
let list = ["red", "green", "blue"]
list.getLongestString()
|
Declaring extensions as members
|
class Host(val hostname: String) {
fun printHostname() { print(hostname) }
}
class Connection(val host: Host, val port: Int) {
fun printPort() { print(port) }
fun Host.printConnectionString() {
printHostname() // calls Host.printHostname()
print(":")
printPort() // calls Connection.printPort()
}
fun connect() {
/*...*/
host.printConnectionString() // calls the extension function
}
}
fun main() {
Connection(Host("kotl.in"), 443).connect()
//Host("kotl.in").printConnectionString(443) // error, the extension function is unavailable outside Connection
}
|
|
class Connection {
fun Host.getConnectionString() {
toString() // calls Host.toString()
this@Connection.toString() // calls Connection.toString()
}
}
|
|
open class Base { }
class Derived : Base() { }
open class BaseCaller {
open fun Base.printFunctionInfo() {
println("Base extension function in BaseCaller")
}
open fun Derived.printFunctionInfo() {
println("Derived extension function in BaseCaller")
}
fun call(b: Base) {
b.printFunctionInfo() // call the extension function
}
}
class DerivedCaller: BaseCaller() {
override fun Base.printFunctionInfo() {
println("Base extension function in DerivedCaller")
}
override fun Derived.printFunctionInfo() {
println("Derived extension function in DerivedCaller")
}
}
fun main() {
BaseCaller().call(Base()) // "Base extension function in BaseCaller"
DerivedCaller().call(Base()) // "Base extension function in DerivedCaller" - dispatch receiver is resolved virtually
DerivedCaller().call(Derived()) // "Base extension function in DerivedCaller" - extension receiver is resolved statically
}
|
|